package com.neuedu.his.common.utils;


import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.*;
import java.sql.Date;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.TemporalAccessor;
import java.util.*;

public class DBUtils {
    private static  String url ;
    private static  String username ;
    private static   String password ;
    private static  String driverClass;

    static {
        ResourceBundle resourceBundle = ResourceBundle.getBundle("jdbc");

        url = resourceBundle.getString("jdbc.url");
        username = resourceBundle.getString("jdbc.username");
        password = resourceBundle.getString("jdbc.password");
        driverClass = resourceBundle.getString("jdbc.driverClass");

    }

    public static Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName(driverClass);
        return DriverManager.getConnection(url, username, password);
    }

    //关闭资源的方法
    public static void  close(ResultSet rs , Statement stmt, Connection conn){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }


    /**
     *  设置对象的值
     *   反射的机制 会破坏  代码的封装 private.....
     * @param obj1  对象
     * @param columnName 设置值的 数据库字段名称
     * @param value  设置属性 的值
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws NoSuchFieldException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    public static void setFileValue( Object obj1 ,String columnName ,Object value  ) throws InstantiationException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
        Class<?> clazz = obj1.getClass();

        //获取字段对应的属性
        Field declaredField = null;

        try{
            declaredField = clazz.getDeclaredField(columnName);
        }catch (Exception e ){
            //遍历属性,查找那个属性有 注解  menu_id
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field declaredFieldItem : declaredFields) {
                ColumnMapping annotation = declaredFieldItem.getAnnotation(ColumnMapping.class);
                if(annotation != null && annotation.value().equals(columnName) ){
                    declaredField = declaredFieldItem;
                    break;
                }
            }
        }


        //属性
        try
        {
        String  fieldName = declaredField.getName();
        //获取属性对象的Set方法 select menu_id ,menu_name  columnName[menu_name]  setMenu_name
        String functionName = "set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);



//        // obj1.deptno = value
//        declaredField.setAccessible(true);//允许给 private 的 修饰属性 赋值
//        declaredField.set(obj1,value);

            Class<?> fieldType = declaredField.getType();
            Method method = clazz.getDeclaredMethod(functionName, fieldType);
            // Object value   java.sql.Data --> java.util.Date    LocalDateTime

            //类型转换
            value =  translateValueType(declaredField,value);

            //setXXXX(java.util.Date 、)
            method.invoke(obj1,value);
        }catch (Exception e){
//         System.out.println("columnName = " + columnName);
//         System.out.println("value = " + value);
//         System.out.println("value.getClass = " + value.getClass());
            e.printStackTrace();
        }
    }

    private static Object translateValueType(Field declaredField, Object value) {
        if(Objects.isNull(value)){
            return  null;
        }

        String fieldType = declaredField.getType().getName();// java.lang.Integer
        String valueType = value.getClass().getName();
        //private Integer userid;
//        System.out.println("declaredField.getName() = " + declaredField.getName()); //userId
//        System.out.println("declaredField.getType().getName() = " + declaredField.getType().getName());//Integer java.lang.Integer
//        System.out.println("value.getClass().getName() = " + value.getClass().getName());



        switch (fieldType){
            case "java.lang.Integer":
                if(value instanceof  Long){
                    Long longValue = (Long) value;
                    //long---Integer
                    return longValue.intValue();
                }
            case "java.util.Date":
                if(value instanceof LocalDateTime){
                    LocalDateTime ldt = (LocalDateTime) value;
                    //LocalDateTime---Date
                    return  Date.from( ldt.atZone( ZoneId.systemDefault()).toInstant());


                }
            case "java.lang.Double":
                if(value instanceof BigDecimal){
                    BigDecimal bd = (BigDecimal) value;
                    //LocalDateTime---Date
                    return  bd.doubleValue();
                }
        }

        return value;
    }


    //     select * from dept where id = ?
    public static <T> T selectOne(Class clazz , String sql ,Object ... params) {
        List<T> list = selectList( clazz ,  sql , params);
        if(list != null && list.size()>0){
            return list.get(0);
        }
        return null;
    }


    //select * from emp
    public static <T> List<T> selectList(Class<T> clazz , String sql ,Object ... params) {
        List<T> list = new ArrayList();
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = getConnection();
            stmt = conn.prepareStatement(sql);

            //绑定变量
            for (int i = 0; i < params.length; i++) {
                stmt.setObject(i + 1, params[i]);
            }
            rs = stmt.executeQuery();

            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();//一共查询结果中有几列

            //让rs指向数据行
            while (rs.next()) {//循环行
                T result = clazz.newInstance();
                for (int i = 1; i <=columnCount; i++) {
                    //获得字段名字
                    String columnName =  metaData.getColumnLabel(i);
                    //给字段对应的 属性 赋值
                    Object value = rs.getObject(columnName);
                    setFileValue(result,columnName,value);
                }
                list.add( result);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } finally {
            close(rs, stmt, conn);
        }

        return list;
    }


    /**
     * 用于 执行  delete  update 、 insert
     * @param sql
     * @param params
     * @return
     */
    public static int update(String sql, Object... params) {
        int count = 0;
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = getConnection();
            stmt = conn.prepareStatement(sql.toString());

            //绑定变量
            for (int i = 0; i < params.length; i++) {
                stmt.setObject(i + 1, params[i]);
            }

            count = stmt.executeUpdate();

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            close(rs, stmt, conn);
        }
        return count;
    }


    public static Map selectMap(String sql, Object... params) {
        Map map = new HashMap();
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = getConnection();
            stmt = conn.prepareStatement(sql);

            //绑定变量
            for (int i = 0; i < params.length; i++) {
                stmt.setObject(i + 1, params[i]);
            }
            rs = stmt.executeQuery();

            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();//一共查询结果中有几列

            //让rs指向数据行
            if (rs.next()) {//循环行

                for (int i = 1; i <=columnCount; i++) {
                    //获得字段名字
                    String columnName =  metaData.getColumnLabel(i);
                    //给字段对应的 属性 赋值
                    Object value = rs.getObject(columnName);
                    map.put(columnName,value);
                }

            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(rs, stmt, conn);
        }

        return map;
    }
}